package com.jinmdz.fmis.api.api.service;

import com.jinmdz.fmis.api.api.model.common.BusinessCharges;
import com.jinmdz.fmis.api.api.model.common.IdData;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.api.model.mourn.*;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.constant.MessageConst;
import com.jinmdz.fmis.api.model.config.dictionary.BusinessLogCode;
import com.jinmdz.fmis.api.model.config.dictionary.HallStatusCode;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.ChargeWrapper;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.common.util.DateUtil;
import com.jinmdz.fmis.common.util.StringUtil;
import com.jinmdz.fmis.core.base.BaseBean;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.constant.Constants;
import com.jinmdz.fmis.core.constant.EBusinessType;
import com.jinmdz.fmis.core.constant.EDictCode;
import com.jinmdz.fmis.core.constant.PurposeConst;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.dao.*;
import com.jinmdz.fmis.dao.model.charge.ChargeItem;
import com.jinmdz.fmis.dao.model.funeral.FuneralBusinessViewItem;
import com.jinmdz.fmis.dao.model.mourn.*;
import com.jinmdz.fmis.dao.model.service.ServiceItem;
import com.jinmdz.fmis.mapper.entity.ChargeItemEntity;
import com.jinmdz.fmis.mapper.entity.FuneralBusinessLogEntity;
import com.jinmdz.fmis.mapper.entity.MournCeremonyEntity;
import com.jinmdz.fmis.mapper.mapper.ChargeItemMapper;
import com.jinmdz.fmis.mapper.mapper.MournCeremonyHallMapper;
import com.jinmdz.fmis.mapper.mapper.MournCeremonyMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;

/**
 * MournCeremonyService类
 *
 * @author LiCongLu
 * @date 2020-01-20 11:09
 */
@Service("mournCeremonyService")
public class MournCeremonyService extends BaseService {

    @Resource
    private FuneralBusinessDao funeralBusinessDao;

    @Resource
    private MournCeremonyMapper mournCeremonyMapper;

    @Resource
    private ChargeItemMapper chargeItemMapper;

    @Resource
    private MournCeremonyHallMapper mournCeremonyHallMapper;

    @Resource
    private HallStatusCode hallStatusCode;

    @Resource
    private ServiceItemDao serviceItemDao;

    @Resource
    private ChargeItemDao chargeItemDao;

    @Resource
    private MournCeremonyDao mournCeremonyDao;

    @Resource
    private MournCeremonyHallDao mournCeremonyHallDao;

    @Resource
    private ChargeWrapper chargeWrapper;

    @Resource
    private DictionaryService dictionaryService;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private BusinessLogCode businessLogCode;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    @Resource
    private DataDictionaryDao dataDictionaryDao;

    /**
     * 根据mourn_ceremony表中id加载礼厅任务信息
     *
     * @param data 礼厅主键
     * @return
     * @author LiCongLu
     * @date 2020-02-15 14:20
     */
    public BaseResult<MournCeremonyData> loadMournCeremonyWithId(IdData data) {
        Integer loadId = data.getId();

        // 查询业务信息
        MournCeremonyViewItem loadItem = mournCeremonyDao.getMournCeremonyViewById(loadId);

        if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
            return failure("主键错误，不存在此业务信息");
        }
        MournCeremonyData loadData = loadMournCeremonyData(loadItem);

        // 返回响应结果
        return successData(loadData);
    }


    /**
     * 获取业务费用等数据
     *
     * @param loadItem 已加载数据
     * @return
     * @author LiCongLu
     * @date 2020-02-16 11:48
     */
    private MournCeremonyData loadMournCeremonyData(MournCeremonyItem loadItem) {
        // 创建响应实体，并赋值
        MournCeremonyData loadData = BeanUtil.copy2Bean(loadItem, new MournCeremonyData());

        // 获取业务费用及物品服务
        loadData.setCharges(new BusinessCharges());

        ChargeItem businessCharge = chargeItemDao.getChargeItemById(loadItem.getChargeId());
        loadData.getCharges().setBusinessCharge(businessCharge);

        // 业务费用主键
        Integer businessChargeId = businessCharge != null ? businessCharge.getId() : 0;

        ArrayList<ChargeItem> goodsServices = chargeItemDao.listChargeItemByRandomCode(loadItem.getBusinessCode(), loadItem.getRandomCode(), businessChargeId);
        loadData.getCharges().setGoodsServices(goodsServices);
        //设置文本值
        dictionaryWrapper.resetDataText(loadData);
        return loadData;
    }

    /**
     * 保存礼厅信息到mourn_ceremony表中
     *
     * @param data 礼厅数据
     * @return
     * @author LiCongLu
     * @date 2020-02-15 15:37
     */
    public BaseResult<MournCeremonyData> saveMournCeremony(UserItem userItem, MournCeremonyData data) throws ActionException {
        String businessCode = data.getBusinessCode();
        // 通过业务编码获取殡葬信息
        FuneralBusinessViewItem funeralItem = funeralBusinessDao.getFuneralBusinessViewByBusinessCode(businessCode);
        if (DataUtil.isNull(funeralItem) || DataUtil.isNull(funeralItem.getId(), funeralItem.getVersion())) {
            throw exception(MessageConst.NO_FUNERAL_CODE);
        }

        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateMournCeremony(userItem, funeralItem, data);
        } else {
            id = insertMournCeremony(userItem, funeralItem, data);
        }
        return loadMournCeremonyWithId(new IdData(id));
    }

    /**
     * 插入礼厅信息
     *
     * @param userItem    当前帐号
     * @param funeralItem 殡葬业务
     * @param data        新增礼厅信息
     * @return
     * @author LiCongLu
     * @date 2020-02-15 15:58
     */
    private Integer insertMournCeremony(UserItem userItem, FuneralBusinessViewItem funeralItem, MournCeremonyData data) throws ActionException {
        // 创建礼厅实体
        MournCeremonyEntity entity = getEntity(userItem, MournCeremonyEntity.class);

        // 判断流程状态
        if (!DataUtil.inIntegers(data.getProcessStateCode()
                , hallStatusCode.getYiYuDing()
                , hallStatusCode.getWeiRuTing()
                , hallStatusCode.getYiRuTing()
                , hallStatusCode.getYiChuTing())) {
            throw exception("礼厅状态值错误");
        }

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 创建业务随机码
        entity.setRandomCode(DataUtil.getUUID());

        // 判断礼厅占用状态
        checkMournCeremonyHall(data);

        // 依照状态等设置默认值
        saveMournCeremonyValue(data, entity);

        // 插入业务费用
        ChargeItem businessCharge = data.getCharges().getBusinessCharge();
        businessCharge.setBusinessCode(entity.getBusinessCode())
                .setRandomCode(entity.getRandomCode())
                .setItemNumber(data.getRuleNumber())
                .setItemUnit(data.getRuleUnit());

        // 验证是否不可结算
        checkBusinessChargeUnsettled(entity, businessCharge);

        String dictCode = EDictCode.HALL_TYPE.getCode();
        String purpose = DataUtil.equals(data.getBusinessType(), Constants.WAKE_MOURN_TYPE) ? PurposeConst.SHOU_LING_TING : PurposeConst.GAO_BIE_TING;
        int chargeId = chargeWrapper.insertBusinessCharge(userItem, businessCharge, dictCode, entity.getHallTypeCode(), purpose, data.getRuleRemark());
        entity.setChargeId(chargeId);

        // 插入物品服务
        ArrayList<ChargeItemEntity> chargeEntities = chargeWrapper.insertGoodsServices(userItem, entity.getBusinessCode(), entity.getRandomCode(), EBusinessType.USE_IN_MOURN_CEREMONY.getType(), data.getCharges().getGoodsServices());

        // 新增礼厅信息
        mournCeremonyMapper.insertMournCeremony(entity);
        // 判断保存礼厅信息结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存礼厅信息失败");
        }

        // 添加业务及操作日志
        boolean mournFlag = Constants.WAKE_MOURN_TYPE.equals(entity.getBusinessType());
        Integer logTypeCode = mournFlag ? operationLogCode.getWakeMournInsert() : operationLogCode.getFarewellMournInsert();
        Integer chargeLogTypeCode = operationLogCode.getChargeInsert();
        saveMournCeremonyLog(userItem, funeralItem, data, entity, mournFlag, logTypeCode, chargeLogTypeCode, businessCharge, chargeEntities, null);

        return entity.getId();
    }

    /**
     * 验证是否不可结算
     *
     * @param entity         数据实体
     * @param businessCharge 业务费用
     * @return
     * @author LiCongLu
     * @date 2020-05-15 10:57
     */
    private void checkBusinessChargeUnsettled(MournCeremonyEntity entity, ChargeItem businessCharge) {
        boolean unsettled = false;
        // 判断条件：1.预约出厅时间为空
        if (DataUtil.isNull(entity.getAppointmentOutTime())) {
            unsettled = true;
        }

        // 设置不可结算状态
        businessCharge.setAsUnsettled(unsettled ? 1 : 0);
    }

    /**
     * 添加冷藏日志记录
     *
     * @param userItem          当前帐号
     * @param funeralItem       当前业务
     * @param data              请求数据
     * @param entity            数据实体
     * @param mournFlag         业务类型标记
     * @param logTypeCode       日志记录类型
     * @param chargeLogTypeCode 费用日志类型
     * @param businessCharge    业务费用
     * @param chargeEntities    费用记录
     * @param deleteEntities    删除费用记录
     * @return
     * @author LiCongLu
     * @date 2020-02-25 14:33
     */
    private void saveMournCeremonyLog(UserItem userItem, FuneralBusinessViewItem funeralItem
            , MournCeremonyData data, MournCeremonyEntity entity
            , boolean mournFlag, Integer logTypeCode, Integer chargeLogTypeCode
            , ChargeItem businessCharge, ArrayList<ChargeItemEntity> chargeEntities, ArrayList<ChargeItemEntity> deleteEntities) throws ActionException {

        // 添加业务日志及操作日志
        String businessCode = funeralItem.getBusinessCode();
        Integer typeCode = getLogTypeForStateCode(mournFlag, entity.getProcessStateCode());
        FuneralBusinessLogEntity businessLogEntity = operationWrapper.businessLog(userItem, businessCode, typeCode);
        String mournType = mournFlag ? "守灵" : "告别";

        // 获取新设备信息
        MournCeremonyHallItem hallItem = mournCeremonyHallDao.getMournCeremonyHallById(entity.getHallId());
        String hallCode = hallItem != null ? hallItem.getHallCode() : "";

        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存{3}信息，业务编码[{0}]，逝者姓名[{1}]，业务类型[{2}][{3}]，礼厅类型[{4}][{5}]，礼厅编号[{6}]" +
                        "，预约入厅时间[{7}]，预约出厅时间[{8}]，礼厅状态[{9}]" +
                        " ，{3}费用[{10}]，操作人员[{11}]"
                , businessCode, funeralItem.getDeadName(), entity.getBusinessType(), mournType
                , String.valueOf(entity.getHallTypeCode())
                , dictionaryWrapper.getDataText(EDictCode.HALL_TYPE, entity.getHallTypeCode())
                , hallCode
                , DateUtil.formatPattern16(entity.getAppointmentInTime()), DateUtil.formatPattern16(entity.getAppointmentOutTime())
                , dictionaryWrapper.getDataText(EDictCode.HALL_STATUS, entity.getProcessStateCode())
                , DataUtil.getPlainString(businessCharge.getItemCharge()), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, businessLogEntity, logTypeCode, builder.toString()
                , JacksonUtil.obj2Json(data), null, JacksonUtil.obj2Json(entity));

        // 累计费用总金额
        if (DataUtil.valid(chargeEntities)) {
            BigDecimal sumCharge = new BigDecimal(0);
            for (ChargeItemEntity chargeEntity : chargeEntities) {
                sumCharge = sumCharge.add(chargeEntity.getItemCharge());
            }
            // 添加物品服务费用日志
            builder.clear();
            builder.format("保存{2}信息更新物品服务，业务编码[{0}]，逝者姓名[{1}]，{2}费用[{3}]，物品服务总金额[{4}]"
                    , businessCode, funeralItem.getDeadName(), mournType
                    , DataUtil.getPlainString(businessCharge.getItemCharge()), DataUtil.getPlainString(sumCharge));
            operationWrapper.operationLog(userItem, businessLogEntity, chargeLogTypeCode
                    , builder.toString(), JacksonUtil.obj2Json(data.getCharges().getGoodsServices()), null, JacksonUtil.obj2Json(chargeEntities));
        }

        // 删除费用总金额
        if (DataUtil.valid(deleteEntities)) {
            BigDecimal sumCharge = new BigDecimal(0);
            for (ChargeItemEntity chargeEntity : deleteEntities) {
                sumCharge = sumCharge.add(chargeEntity.getItemCharge());
            }
            // 删除物品服务费用日志
            builder.clear();
            builder.format("保存{2}信息删除物品服务，业务编码[{0}]，逝者姓名[{1}]，删除物品服务总金额[{2}]"
                    , businessCode, funeralItem.getDeadName(), mournType, DataUtil.getPlainString(sumCharge));
            operationWrapper.operationLog(userItem, businessLogEntity, operationLogCode.getChargeDelete()
                    , builder.toString(), null, JacksonUtil.obj2Json(deleteEntities), null);
        }
    }

    /**
     * 验证流程状态值
     *
     * @param stateCode 流程状态值
     * @param mournFlag 业务类型标记
     * @return
     * @author LiCongLu
     * @date 2020-02-24 17:20
     */
    private Integer getLogTypeForStateCode(boolean mournFlag, int stateCode) throws ActionException {
        // 处理状态
        if (DataUtil.equals(stateCode, hallStatusCode.getYiYuDing())) {
            return mournFlag ? businessLogCode.getWakeMournYiYuDing() : businessLogCode.getFarewellMournYiYuDing();
        } else if (DataUtil.equals(stateCode, hallStatusCode.getWeiRuTing())) {
            return mournFlag ? businessLogCode.getWakeMournWeiRuTing() : businessLogCode.getFarewellMournWeiRuTing();
        } else if (DataUtil.equals(stateCode, hallStatusCode.getYiRuTing())) {
            return mournFlag ? businessLogCode.getWakeMournYiRuTing() : businessLogCode.getFarewellMournYiRuTing();
        } else if (DataUtil.equals(stateCode, hallStatusCode.getYiChuTing())) {
            return mournFlag ? businessLogCode.getWakeMournYiChuTing() : businessLogCode.getFarewellMournYiChuTing();
        } else {
            throw exception("流转状态值错误");
        }
    }

    /**
     * 依据状态等设置默认值
     *
     * @param entity 数据实体
     * @return
     * @author LiCongLu
     * @date 2020-02-17 17:31
     */
    private void saveMournCeremonyValue(MournCeremonyData data, MournCeremonyEntity entity) throws ActionException {

        Date nowDate = nowDate();
        // 处理状态
        int stateCode = data.getProcessStateCode();
        if (DataUtil.equals(stateCode, hallStatusCode.getYiYuDing())) {

        } else if (DataUtil.equals(stateCode, hallStatusCode.getWeiRuTing())) {
        } else if (DataUtil.equals(stateCode, hallStatusCode.getYiRuTing())) {
            if (DataUtil.isNull(entity.getRealityInTime())) {
                // 已入厅状态，但未填写实际入厅时间的，设置实际入厅时间
                entity.setRealityInTime(nowDate);
            }
        } else if (DataUtil.equals(stateCode, hallStatusCode.getYiChuTing())) {
            if (DataUtil.isNull(entity.getRealityOutTime())) {
                // 已出厅状态，但未填写实际出厅时间的，设置实际出厅时间
                entity.setRealityOutTime(nowDate);
            }
        } else {
            throw exception("流转状态值错误");
        }

        // 判断预约时间
        if (!DataUtil.equals(stateCode, hallStatusCode.getYiYuDing())) {
            // 预约设备主键不能为空
            if (DataUtil.invalid(data.getHallId())) {
                throw exception("礼厅主键不能为空！");
            }

            // 预约时间不能为空
            if (DataUtil.isNull(data.getAppointmentInTime())) {
                throw exception("预约入厅时间不能为空！");
            }

            // 判断已出厅
            if (DataUtil.equals(stateCode, hallStatusCode.getYiChuTing())) {
                // 预约出厅时间不能为空
                if (DataUtil.isNull(data.getAppointmentOutTime())) {
                    throw exception("已出厅时，预约出厅时间不能为空！");
                }
            }
        }

        // 判断时间节点
        if (data.getAppointmentInTime() != null && data.getAppointmentOutTime() != null) {
            if (data.getAppointmentInTime().after(data.getAppointmentOutTime())) {
                throw exception("预约入厅时间晚于预约出厅时间");
            }
        }
    }

    /**
     * 新增验证礼厅
     *
     * @param data 请求数据
     * @return
     * @author LiCongLu
     * @date 2020-02-17 17:31
     */
    private void checkMournCeremonyHall(MournCeremonyData data) throws ActionException {
        if (DataUtil.valid(data.getHallId())) {
            // 获取新礼厅信息
            MournCeremonyHallItem dataItem = mournCeremonyHallDao.getMournCeremonyHallById(data.getHallId());
            if (DataUtil.isNull(dataItem) || DataUtil.isNull(dataItem.getId(), dataItem.getVersion())) {
                throw exception("礼厅房间主键错误，不存在此礼厅信息");
            }

            // 判断礼厅类型
            if (!DataUtil.equals(dataItem.getHallTypeCode(), data.getHallTypeCode())) {
                throw exception("礼厅房间类型与礼厅所属类型不一致");
            }

            // 判断是否有效使用
            if (DataUtil.valid(dataItem.getDisableState())) {
                throw exception("礼厅房间是无效禁用状态");
            }

            // 当已经入厅时，判断当前时间内是否被占用
            if (!DataUtil.equals(data.getProcessStateCode(), hallStatusCode.getYiChuTing())) {
                // 当已入厅时，判断是否已经入厅；当非已入厅时，只按照时间判断
                Integer inState = DataUtil.equals(data.getProcessStateCode(), hallStatusCode.getYiChuTing()) ? hallStatusCode.getYiRuTing() : -1;
                // 设备占用情况
                Integer businessId = mournCeremonyDao.getBusinessIdForHallId(data.getHallId()
                        , data.getId(), hallStatusCode.getYiChuTing(), inState, data.getAppointmentInTime(), data.getAppointmentOutTime());
                if (DataUtil.valid(businessId)) {
                    throw exception("礼厅房间是占用状态，不可使用");
                }
            }
        }
    }

    /**
     * 更新礼厅信息
     *
     * @param userItem    当前帐号
     * @param funeralItem 殡葬业务
     * @param data        更新礼厅信息
     * @return
     * @author LiCongLu
     * @date 2020-02-15 10:59
     */
    private void updateMournCeremony(UserItem userItem, FuneralBusinessViewItem funeralItem, MournCeremonyData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求礼厅信息主键与版本号不能为空");
        }

        // 判断礼厅费用
        ChargeItem businessCharge = data.getCharges().getBusinessCharge();
        if (DataUtil.invalid(businessCharge.getId())) {
            throw exception("请求礼厅费用主键不能为空");
        }

        // 通过主键获取礼厅信息
        MournCeremonyEntity entity = mournCeremonyMapper.getMournCeremonyById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("礼厅主键错误，不存在此礼厅信息");
        }

        // 验证业务编码
        if (!data.getBusinessCode().equals(entity.getBusinessCode())) {
            throw exception(MessageConst.BUSINESS_CODE_ERROR);
        }

        // 验证礼厅信息版本
        if (!DataUtil.equals(data.getVersion(), entity.getVersion())) {
            throw exception(versionError("礼厅信息"));
        }

        // 验证业务与业务费用是否匹配
        if (businessCharge.getId().intValue() != entity.getChargeId().intValue()
                || !businessCharge.getBusinessCode().equals(entity.getBusinessCode())) {
            throw exception("业务费用与业务不匹配");
        }

        // 判断流程状态
        if (!DataUtil.inIntegers(data.getProcessStateCode()
                , hallStatusCode.getYiYuDing()
                , hallStatusCode.getWeiRuTing()
                , hallStatusCode.getYiRuTing()
                , hallStatusCode.getYiChuTing())) {
            throw exception("礼厅状态值错误");
        }

        if (data.getProcessStateCode().intValue() < entity.getProcessStateCode().intValue()) {
            throw exception("礼厅状态值不允许回退选择");
        }

        // 依照状态等设置默认值
        saveMournCeremonyValue(data, entity);

        // 判断礼厅占用状态
        checkMournCeremonyHall(data);

        // 业务费用
        ChargeItem chargeItem = chargeItemDao.getChargeItemById(entity.getChargeId());

        // 判断礼厅及状态
        updateMournCeremonyHallState(userItem, DataUtil.valid(chargeItem.getAsSettled()), data, entity);

        // 更新业务费用
        businessCharge.setBusinessCode(entity.getBusinessCode())
                .setRandomCode(entity.getRandomCode())
                .setItemNumber(data.getRuleNumber())
                .setItemUnit(data.getRuleUnit())
                .setId(entity.getChargeId());

        // 验证是否不可结算
        checkBusinessChargeUnsettled(entity, businessCharge);

        String dictCode = EDictCode.HALL_TYPE.getCode();
        String purpose = DataUtil.equals(data.getBusinessType(), Constants.WAKE_MOURN_TYPE) ? PurposeConst.SHOU_LING_TING : PurposeConst.GAO_BIE_TING;
        chargeWrapper.updateBusinessCharge(userItem, businessCharge, dictCode, data.getHallTypeCode(), purpose, data.getRuleRemark());

        // 业务费用主键
        Integer businessChargeId = businessCharge != null ? businessCharge.getId() : 0;

        // 更新物品服务
        ArrayList<ChargeItemEntity> chargeEntities = chargeWrapper.updateGoodsServices(userItem, entity.getBusinessCode(), entity.getRandomCode(), EBusinessType.USE_IN_MOURN_CEREMONY.getType(), businessChargeId, data.getCharges().getGoodsServices());

        // 删除物品服务
        ArrayList<ChargeItemEntity> deleteEntities = chargeWrapper.deleteGoodsServices(userItem, entity.getBusinessCode(), entity.getRandomCode(), EBusinessType.USE_IN_MOURN_CEREMONY.getType(), data.getCharges().getDeleteIds());

        // 设置修改帐号
        entity.setModifiedUserId(userItem.getId());
        // 更新礼厅信息
        mournCeremonyMapper.updateMournCeremony(entity);

        // 添加业务及操作日志
        boolean mournFlag = Constants.WAKE_MOURN_TYPE.equals(entity.getBusinessType());
        Integer logTypeCode = mournFlag ? operationLogCode.getWakeMournInsert() : operationLogCode.getFarewellMournInsert();
        Integer chargeLogTypeCode = operationLogCode.getChargeInsert();
        saveMournCeremonyLog(userItem, funeralItem, data, entity, mournFlag, logTypeCode, chargeLogTypeCode, businessCharge, chargeEntities, deleteEntities);
    }

    /**
     * 更新验证礼厅
     *
     * @param userItem 当期账号
     * @param settled  是否结算
     * @param data     请求数据
     * @param entity   保存实体
     * @return
     * @author LiCongLu
     * @date 2020-02-17 11:18
     */
    private void updateMournCeremonyHallState(UserItem userItem, boolean settled, MournCeremonyData data, MournCeremonyEntity entity) throws ActionException {

        // 依据业务费用更新变化，即是否结算了，来处理数据覆盖情况
        if (settled) {
            // 已结算，覆盖部分数据
            // 已结算的不能修改礼厅类型
            if (!DataUtil.equals(data.getHallTypeCode(), entity.getHallTypeCode())) {
                throw exception("已结算不能修改礼厅房间类型");
            }

            // 已结算，只能修改状态
            entity.setProcessStateCode(data.getProcessStateCode());
            return;
        }

        // 如果原状态是已入厅等状态，预约入厅时间不修改
        if (DataUtil.inIntegers(entity.getProcessStateCode()
                , hallStatusCode.getYiRuTing())) {
            data.setAppointmentInTime(entity.getAppointmentInTime());
        }

        // 如果原状态是已出厅等状态，预约入厅时间和预约出厅时间不修改
        if (DataUtil.inIntegers(entity.getProcessStateCode()
                , hallStatusCode.getYiChuTing())) {
            data.setAppointmentInTime(entity.getAppointmentInTime())
                    .setAppointmentOutTime(entity.getAppointmentOutTime());
        }

        // 未结算，覆盖数据
        BeanUtil.copy2Bean(data, entity);
    }

    /**
     * 从mourn_ceremony表中删除指定id的礼厅任务信息记录
     *
     * @param data 主键和版本号
     * @return
     * @author LiCongLu
     * @date 2020-02-15 14:37
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteMournCeremonyWithId(UserItem userItem, IdVersionData data) throws ActionException {
        // 通过主键获取礼厅信息
        MournCeremonyViewItem loadItem = mournCeremonyDao.getMournCeremonyViewById(data.getId());
        if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
            return failure("主键错误，不存在此礼厅业务信息");
        }

        // 验证礼厅信息版本
        if (!DataUtil.equals(loadItem.getVersion(), data.getVersion())) {
            return failure(versionError("礼厅信息"));
        }

        // 验证状态，已入厅、已出厅等状态不能删除
        if (DataUtil.inIntegers(loadItem.getProcessStateCode(), hallStatusCode.getYiRuTing(), hallStatusCode.getYiChuTing())) {
            return failure("已入厅、已出厅等状态不能删除");
        }

        // 记录费用主键
        ArrayList<Integer> chargeIds = new ArrayList<>();
        // 判断业务费用是否存在
        ChargeItem businessCharge = chargeItemDao.getChargeItemById(loadItem.getChargeId());
        if (businessCharge != null) {
            // 判断是否结算
            if (DataUtil.valid(businessCharge.getAsSettled())) {
                return failure("礼厅业务费用已经结算，无法进行删除");
            }
            chargeIds.add(businessCharge.getId());
        }

        // 业务费用主键
        Integer businessChargeId = businessCharge != null ? businessCharge.getId() : 0;

        // 判断是否已经存在结算
        ArrayList<ChargeItem> goodsServices = chargeItemDao.listChargeItemByRandomCode(loadItem.getBusinessCode(), loadItem.getRandomCode(), businessChargeId);
        if (DataUtil.valid(goodsServices)) {
            for (ChargeItem chargeItem : goodsServices) {
                if (DataUtil.valid(chargeItem.getAsSettled())) {
                    return failure("礼厅物品服务已经结算，无法进行删除");
                }
                chargeIds.add(chargeItem.getId());
            }
        }

        // 删除费用
        if (chargeIds.size() > 0) {
            chargeItemDao.deletedForChargeItem(loadItem.getBusinessCode(), chargeIds, userItem.getId());
        }

        // 删除业务任务
        mournCeremonyMapper.deletedForMournCeremony(loadItem.getId(), userItem.getId(), loadItem.getVersion());

        // 删除日志信息
        deleteMournCeremonyLog(userItem, loadItem, businessCharge, goodsServices);

        return success("删除完成");
    }

    /**
     * 删除礼厅日志
     *
     * @param userItem       当前账号
     * @param loadItem       礼厅任务
     * @param businessCharge 业务费用
     * @param goodsServices  物品服务
     * @return
     * @author LiCongLu
     * @date 2020-02-25 17:30
     */
    private void deleteMournCeremonyLog(UserItem userItem, MournCeremonyItem loadItem, ChargeItem businessCharge, ArrayList<ChargeItem> goodsServices) throws ActionException {
        // 添加业务日志及操作日志
        String businessCode = loadItem.getBusinessCode();
        boolean mournFlag = Constants.WAKE_MOURN_TYPE.equals(loadItem.getBusinessType());
        String mournType = mournFlag ? PurposeConst.SHOU_LING_TING : PurposeConst.GAO_BIE_TING;
        Integer typeCode = mournFlag ? businessLogCode.getWakeMournDelete() : businessLogCode.getFarewellMournDelete();
        FuneralBusinessLogEntity businessLogEntity = operationWrapper.businessLog(userItem, businessCode, typeCode);
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除{3}信息，业务编码[{0}]，操作人员[{1}]", businessCode, userItem.getFullName(), mournType);

        // 添加日志
        Integer logTypeCode = mournFlag ? operationLogCode.getWakeMournDelete() : operationLogCode.getFaceLiftDelete();
        operationWrapper.operationLog(userItem, businessLogEntity, logTypeCode, builder.toString(), null, JacksonUtil.obj2Json(loadItem), null);

        // 累计费用总金额
        if (DataUtil.valid(goodsServices)) {
            Integer chargeLogTypeCode = operationLogCode.getChargeDelete();
            BigDecimal sumCharge = new BigDecimal(0);
            for (ChargeItem chargeItem : goodsServices) {
                sumCharge = sumCharge.add(chargeItem.getItemCharge());
            }
            // 记录业务费用
            goodsServices.add(businessCharge);
            // 添加物品服务费用日志
            builder.clear();
            builder.format("删除{1}信息物品服务，业务编码[{0}]，{1}费用[{2}]，物品服务总金额[{3}]", businessCode
                    , mournType, DataUtil.getPlainString(businessCharge.getItemCharge()), DataUtil.getPlainString(sumCharge));
            operationWrapper.operationLog(userItem, businessLogEntity, chargeLogTypeCode
                    , builder.toString(), null, JacksonUtil.obj2Json(goodsServices), null);
        }
    }

    /**
     * 根据礼厅类型加载守灵礼厅信息
     *
     * @param data 类型
     * @return
     * @author LiCongLu
     * @date 2020-03-08 18:04
     */
    public BaseResult<ArrayList<MournCeremonyWakeHallItem>> loadMournCeremonyWakeHallWithDate(MournCeremonyHallDateData data) {
        ArrayList<MournCeremonyHallDeadItem> loadItems = mournCeremonyHallDao.listMournCeremonyHallDeadByDataCode(data.getHallTypeCode()
                , hallStatusCode.getYiChuTing(), -1, data.getAppointmentInTime(), data.getAppointmentOutTime(), 1, 0);

        // 简化查询结果
        ArrayList<MournCeremonyWakeHallItem> loadViewItems = BeanUtil.copy2List(loadItems, MournCeremonyWakeHallItem.class);

        // 设置字典文本
        dictionaryWrapper.resetDataText(loadViewItems);
        // 返回响应结果
        return successList(loadViewItems);
    }

    /**
     * 根据礼厅类型加载告别厅礼厅信息
     *
     * @param data 类型
     * @return
     * @author LiCongLu
     * @date 2020-03-08 18:04
     */
    public BaseResult<ArrayList<MournCeremonyFarewellHallItem>> loadMournCeremonyFarewellHallWithDate(MournCeremonyHallDateData data) {
        ArrayList<MournCeremonyHallDeadItem> loadItems = mournCeremonyHallDao.listMournCeremonyHallDeadByDataCode(data.getHallTypeCode()
                , hallStatusCode.getYiChuTing(), -1, data.getAppointmentInTime(), data.getAppointmentOutTime(), 0, 1);

        // 简化查询结果
        ArrayList<MournCeremonyFarewellHallItem> loadViewItems = BeanUtil.copy2List(loadItems, MournCeremonyFarewellHallItem.class);

        // 告别厅主键
        ArrayList<Integer> hallIds = new ArrayList<>();
        for (MournCeremonyFarewellHallItem loadViewItem : loadViewItems) {
            hallIds.add(loadViewItem.getId());
        }

        // 如果存在告别厅
        if (DataUtil.valid(hallIds)) {
            // 获取告别厅信息
            ArrayList<MournCeremonyDeadItem> mournDeadItems = mournCeremonyHallDao.listMournCeremonyDeadByHallIds(hallIds, data.getAppointmentInTime());
            // 遍历设置逝者列表
            for (MournCeremonyFarewellHallItem loadViewItem : loadViewItems) {
                ArrayList<String> appointmentList = new ArrayList<>();
                Iterator<MournCeremonyDeadItem> iterator = mournDeadItems.iterator();
                while (iterator.hasNext()) {
                    MournCeremonyDeadItem mournDeadItem = iterator.next();
                    if (DataUtil.equals(mournDeadItem.getHallId(), loadViewItem.getId())) {
                        appointmentList.add(StringUtil.format("【{0}】{1}", mournDeadItem.getDeadName(), DateUtil.formatPattern(mournDeadItem.getAppointmentInTime(), BaseBean.yyyy_MM_dd_HH_mm)));
                        iterator.remove();
                    }
                }
                loadViewItem.setAppointmentList(appointmentList);
            }
        }

        // 设置字典文本
        dictionaryWrapper.resetDataText(loadViewItems);

        // 返回响应结果
        return successList(loadViewItems);
    }

    /**
     * 界面权限验证及基础数据加载
     *
     * @param data 加载全部数据
     * @return
     * @author LiCongLu
     * @date 2020-02-16 11:46
     */
    public BaseResult<MournCeremonyAllLoadData> loadMournCeremonyAll(MournCeremonyAllData data) {
        String businessCode = data.getBusinessCode();
        // 通过业务编码获取殡葬信息
        FuneralBusinessViewItem funeralItem = funeralBusinessDao.getFuneralBusinessViewByBusinessCode(businessCode);
        if (DataUtil.isNull(funeralItem) || DataUtil.isNull(funeralItem.getId(), funeralItem.getVersion())) {
            return failure(MessageConst.NO_FUNERAL_CODE);
        }

        MournCeremonyAllLoadData allLoadData = new MournCeremonyAllLoadData();

        // 加载业务数据
        if (DataUtil.valid(data.getMournCeremonyId())) {
            // 查询业务信息
            MournCeremonyViewItem loadItem = mournCeremonyDao.getMournCeremonyViewById(data.getMournCeremonyId());
            if (DataUtil.noNullOrEmpty(loadItem)) {
                // 验证业务编码
                if (!businessCode.equals(loadItem.getBusinessCode())) {
                    return failure(MessageConst.BUSINESS_CODE_ERROR);
                }

                // 验证业务类型
                if (!data.getBusinessType().equals(loadItem.getBusinessType())) {
                    return failure("请求业务类型与业务主键所指业务类型不一致");
                }
                MournCeremonyData loadData = loadMournCeremonyData(loadItem);
                allLoadData.setMournCeremony(loadData);
            }
        }

        // 加载字典数据
        allLoadData.setDicts(dictionaryService.loadDictionaryMap(data.getDictTypeCodes()));

        // 加载服务规则
        String dictCode = EDictCode.HALL_TYPE.getCode();
        String purpose = DataUtil.equals(data.getBusinessType(), Constants.WAKE_MOURN_TYPE) ? PurposeConst.SHOU_LING_TING : PurposeConst.GAO_BIE_TING;
        allLoadData.setRuleItems(serviceItemDao.listServiceDictionaryRuleByDictCode(dictCode, purpose));

        // 记载物品服务
        if (DataUtil.valid(data.getServiceItemTypeCode())) {
            String businessType = EBusinessType.USE_IN_MOURN_CEREMONY.getType();
            ArrayList<ServiceItem> serviceItems = serviceItemDao.listServiceItemByBusinessType(businessType);
            HashMap<String, ArrayList<ServiceItem>> dataMap = new HashMap<>(16);
            dataMap.put(businessType, serviceItems);
            allLoadData.setServiceItems(dataMap);
        }

        // 返回响应结果
        return successData(allLoadData);
    }
}
